package com.zws.cucumber.spring.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.test.context.event.BeforeTestMethodEvent;
import org.springframework.test.context.event.annotation.BeforeTestMethod;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * author: zws
 */
@Configuration
public class ZwsCommonConf implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(ZwsCommonConf.class);

    private static volatile ApplicationContext applicationContext;

    private static ExecutorService executorService = Executors.newFixedThreadPool(4);
    private static List<CompletableFuture<Void>> resourceInitFutures = new ArrayList<>();

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static void asyncInitResource(Runnable runnable) {
        resourceInitFutures.add(CompletableFuture.runAsync(runnable, executorService));
    }

    @Bean
    public RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setConnectTimeout(60_000);
        requestFactory.setReadTimeout(60_000);

        RestTemplate restTemplate = BeanUtils.instantiateClass(RestTemplate.class);
        restTemplate.setRequestFactory(requestFactory);
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            @Override public void handleError(ClientHttpResponse response) throws IOException {
            }
        });
        return restTemplate;
    }

    @Bean
    public Object syncOnResourceAsyncInitPhase() throws ExecutionException, InterruptedException, TimeoutException {
        try {
            Void v = CompletableFuture.allOf(resourceInitFutures.toArray(new CompletableFuture[0])).get(300, TimeUnit.SECONDS);

            return v;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }
    
    @Bean
    public BeanFactoryPostProcessor ctAddingDependsOnBeanFactoryPostProcessor() {
        return (beanFactory) -> {
            List<String> newDependsOnList = new ArrayList<>();
            for (String beanName : Arrays.asList("cassandraServer", "embeddedKafkaBroker", "wireMockServer")) {
                if (beanFactory.containsBeanDefinition(beanName)) {
                    newDependsOnList.add(beanName);
                }
            }
            BeanDefinition bd = beanFactory.getBeanDefinition("syncOnResourceAsyncInitPhase");
            bd.setDependsOn(newDependsOnList.toArray(new String[0]));
            logger.info("add dependsOn for bean 'syncOnResourceAsyncInitPhase': {}", newDependsOnList);

//            if (beanFactory.containsBeanDefinition("embeddedKafkaBroker")) {
//                ZwsKafkaConf.injectEnv();
//            }
        };
    }

    @BeforeTestMethod()
    public void beforeTestMethod(BeforeTestMethodEvent event) {
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
